package jp.tkym.labs.proc;

import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import jp.tkym.labs.proc.PreparedMessageProcesser.PrecallTask;
import jp.tkym.labs.proc.PreparedMessageProcesser.PreparedExit;
import jp.tkym.labs.proc.PreparedMessageProcesser.PreparedMain;
import jp.tkym.labs.proc.PreparedMessageProcesser.PreparedMessage;

class PreparedBooting {
	private String[] args;
	private ExecutorService	precallExecutor = Executors.newSingleThreadExecutor();
	private List<Future<?>> precallFutures = new ArrayList<Future<?>>();
	private Future<PreparedMessage> waitFuture = null;
	
	PreparedBooting(String... args){
		this.args = args;
	}
	
	Callable<PreparedMessage> waitMessage(){
		return new Callable<PreparedMessage>() {
			@Override
			public PreparedMessage call() throws Exception {
				ObjectInputStream ois = new ObjectInputStream(System.in);
				while(true){
					Object obj = ois.readObject();
					if(obj != null){
						if(!(obj instanceof PreparedMessage))
							throw new IllegalArgumentException("objects type is not " + PreparedMessage.class.getName());
						PreparedMessage message = (PreparedMessage) obj;
						if(message instanceof PrecallTask) submitTask((PrecallTask) message);
						if(message instanceof PreparedMain) return (PreparedMain) message;
						if(message instanceof PreparedExit) return (PreparedExit) message;
					}
				}
			}
		};
	}
	
	private void submitTask(PrecallTask task) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
		Object runnable = Class.forName(task.className()).newInstance();
		precallFutures.add(precallExecutor.submit((Runnable) runnable));
	}
	
	void run(){
		ExecutorService	waitMessageExecutor = Executors.newSingleThreadExecutor();
		waitFuture = waitMessageExecutor.submit(waitMessage());
		try {
			PreparedMessage event = waitFuture.get();
			waitMessageExecutor.shutdown();
			
			for(Future<?> future : precallFutures) future.get();
			precallExecutor.shutdown();
			
			if(!(event instanceof PreparedMain)) System.exit(0);
			
			PreparedMain main = (PreparedMain) event;
			Thread.currentThread().setName(main.className());
			new PreparedMessageProcesser()
				.asMain(main)
				.properties(main.properties())
				.invoke(args);
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(-1);
		}
	}
	
	public static void main(String[] args) {
		new PreparedBooting(args).run();
	}
}